home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mgr / sparcmgr / demo2.zoo / demo / ex / exrecover.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-08-06  |  15.7 KB  |  789 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7. #ifndef lint
  8. char *copyright =
  9. "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  10.  All rights reserved.\n";
  11. #endif not lint
  12.  
  13. #ifndef lint
  14. static char *sccsid = "@(#)exrecover.c    7.9 (Berkeley) 6/7/85; 1.2 (Bellcore)    86/08/06";
  15. #endif not lint
  16.  
  17. #include <stdio.h>    /* mjm: BUFSIZ: stdio = 512, VMUNIX = 1024 */
  18. #undef    BUFSIZ        /* mjm: BUFSIZ different */
  19. #undef    EOF        /* mjm: EOF and NULL effectively the same */
  20. #undef    NULL
  21.  
  22. #include "ex.h"
  23. #include "ex_temp.h"
  24. #include "ex_tty.h"
  25. #include <sys/dir.h>
  26. #include "uparm.h"
  27.  
  28. char xstr[1];        /* make loader happy */
  29. short tfile = -1;    /* ditto */
  30.  
  31. /*
  32.  *
  33.  * This program searches through the specified directory and then
  34.  * the directory usrpath(spool/preserve) looking for an instance of the specified
  35.  * file from a crashed editor or a crashed system.
  36.  * If this file is found, it is unscrambled and written to
  37.  * the standard output.
  38.  *
  39.  * If this program terminates without a "broken pipe" diagnostic
  40.  * (i.e. the editor doesn't die right away) then the buffer we are
  41.  * writing from is removed when we finish.  This is potentially a mistake
  42.  * as there is not enough handshaking to guarantee that the file has actually
  43.  * been recovered, but should suffice for most cases.
  44.  */
  45.  
  46. /*
  47.  * For lint's sake...
  48.  */
  49. #ifndef lint
  50. #define    ignorl(a)    a
  51. #endif
  52.  
  53. /*
  54.  * This directory definition also appears (obviously) in expreserve.c.
  55.  * Change both if you change either.
  56.  */
  57. char    mydir[] =    usrpath(spool/preserve);
  58.  
  59. /*
  60.  * Limit on the number of printed entries
  61.  * when an, e.g. ``ex -r'' command is given.
  62.  */
  63. #define    NENTRY    50
  64.  
  65. char    *ctime();
  66. char    nb[BUFSIZ];
  67. int    vercnt;            /* Count number of versions of file found */
  68.  
  69. main(argc, argv)
  70.     int argc;
  71.     char *argv[];
  72. {
  73.     register char *cp;
  74.     register int b, i;
  75.  
  76.     /*
  77.      * Initialize as though the editor had just started.
  78.      */
  79.     fendcore = (line *) sbrk(0);
  80.     dot = zero = dol = fendcore;
  81.     one = zero + 1;
  82.     endcore = fendcore - 2;
  83.     iblock = oblock = -1;
  84.  
  85.     /*
  86.      * If given only a -r argument, then list the saved files.
  87.      */
  88.     if (argc == 2 && eq(argv[1], "-r")) {
  89.         listfiles(mydir);
  90.         exit(0);
  91.     }
  92.     if (argc != 3)
  93.         error(" Wrong number of arguments to exrecover", 0);
  94.  
  95.     CP(file, argv[2]);
  96.  
  97.     /*
  98.      * Search for this file.
  99.      */
  100.     findtmp(argv[1]);
  101.  
  102.     /*
  103.      * Got (one of the versions of) it, write it back to the editor.
  104.      */
  105.     cp = ctime(&H.Time);
  106.     cp[19] = 0;
  107.     fprintf(stderr, " [Dated: %s", cp);
  108.     fprintf(stderr, vercnt > 1 ? ", newest of %d saved]" : "]", vercnt);
  109.     H.Flines++;
  110.  
  111.     /*
  112.      * Allocate space for the line pointers from the temp file.
  113.      */
  114.     if ((int) sbrk((int) (H.Flines * sizeof (line))) == -1)
  115.         /*
  116.          * Good grief.
  117.          */
  118.         error(" Not enough core for lines", 0);
  119. #ifdef DEBUG
  120.     fprintf(stderr, "%d lines\n", H.Flines);
  121. #endif
  122.  
  123.     /*
  124.      * Now go get the blocks of seek pointers which are scattered
  125.      * throughout the temp file, reconstructing the incore
  126.      * line pointers at point of crash.
  127.      */
  128.     b = 0;
  129.     while (H.Flines > 0) {
  130.         ignorl(lseek(tfile, (long) blocks[b] * BUFSIZ, 0));
  131.         i = H.Flines < BUFSIZ / sizeof (line) ?
  132.             H.Flines * sizeof (line) : BUFSIZ;
  133.         if (read(tfile, (char *) dot, i) != i) {
  134.             perror(nb);
  135.             exit(1);
  136.         }
  137.         dot += i / sizeof (line);
  138.         H.Flines -= i / sizeof (line);
  139.         b++;
  140.     }
  141.     dot--; dol = dot;
  142.  
  143.     /*
  144.      * Sigh... due to sandbagging some lines may really not be there.
  145.      * Find and discard such.  This shouldn't happen much.
  146.      */
  147.     scrapbad();
  148.  
  149.     /*
  150.      * Now if there were any lines in the recovered file
  151.      * write them to the standard output.
  152.      */
  153.     if (dol > zero) {
  154.         addr1 = one; addr2 = dol; io = 1;
  155.         putfile(0);
  156.     }
  157.  
  158.     /*
  159.      * Trash the saved buffer.
  160.      * Hopefully the system won't crash before the editor
  161.      * syncs the new recovered buffer; i.e. for an instant here
  162.      * you may lose if the system crashes because this file
  163.      * is gone, but the editor hasn't completed reading the recovered
  164.      * file from the pipe from us to it.
  165.      *
  166.      * This doesn't work if we are coming from an non-absolute path
  167.      * name since we may have chdir'ed but what the hay, noone really
  168.      * ever edits with temporaries in "." anyways.
  169.      */
  170.     if (nb[0] == '/')
  171.         ignore(unlink(nb));
  172.  
  173.     /*
  174.      * Adieu.
  175.      */
  176.     exit(0);
  177. }
  178.  
  179. /*
  180.  * Print an error message (notably not in error
  181.  * message file).  If terminal is in RAW mode, then
  182.  * we should be writing output for "vi", so don't print
  183.  * a newline which would screw up the screen.
  184.  */
  185. /*VARARGS2*/
  186. error(str, inf)
  187.     char *str;
  188.     int inf;
  189. {
  190.  
  191.     fprintf(stderr, str, inf);
  192. #ifndef USG3TTY
  193.     gtty(2, &tty);
  194.     if ((tty.sg_flags & RAW) == 0)
  195. #else
  196.     ioctl(2, TCGETA, &tty);
  197.     if (tty.c_lflag & ICANON)
  198. #endif
  199.         fprintf(stderr, "\n");
  200.     exit(1);
  201. }
  202.  
  203. /*
  204.  * Here we save the information about files, when
  205.  * you ask us what files we have saved for you.
  206.  * We buffer file name, number of lines, and the time
  207.  * at which the file was saved.
  208.  */
  209. struct svfile {
  210.     char    sf_name[FNSIZE + 1];
  211.     int    sf_lines;
  212.     char    sf_entry[MAXNAMLEN + 1];
  213.     time_t    sf_time;
  214. };
  215.  
  216. listfiles(dirname)
  217.     char *dirname;
  218. {
  219.     register DIR *dir;
  220.     struct direct *dirent;
  221.     int ecount, qucmp();
  222.     register int f;
  223.     char *cp;
  224.     struct svfile *fp, svbuf[NENTRY];
  225.  
  226.     /*
  227.      * Open usrpath(spool/preserve), and go there to make things quick.
  228.      */
  229.     dir = opendir(dirname);
  230.     if (dir == NULL) {
  231.         perror(dirname);
  232.         return;
  233.     }
  234.     if (chdir(dirname) < 0) {
  235.         perror(dirname);
  236.         return;
  237.     }
  238.  
  239.     /*
  240.      * Look at the candidate files in usrpath(spool/preserve).
  241.      */
  242.     fp = &svbuf[0];
  243.     ecount = 0;
  244.     while ((dirent = readdir(dir)) != NULL) {
  245.         if (dirent->d_name[0] != 'E')
  246.             continue;
  247. #ifdef DEBUG
  248.         fprintf(stderr, "considering %s\n", dirent->d_name);
  249. #endif
  250.         /*
  251.          * Name begins with E; open it and
  252.          * make sure the uid in the header is our uid.
  253.          * If not, then don't bother with this file, it can't
  254.          * be ours.
  255.          */
  256.         f = open(dirent->d_name, 0);
  257.         if (f < 0) {
  258. #ifdef DEBUG
  259.             fprintf(stderr, "open failed\n");
  260. #endif
  261.             continue;
  262.         }
  263.         if (read(f, (char *) &H, sizeof H) != sizeof H) {
  264. #ifdef DEBUG
  265.             fprintf(stderr, "culdnt read hedr\n");
  266. #endif
  267.             ignore(close(f));
  268.             continue;
  269.         }
  270.         ignore(close(f));
  271.         if (getuid() != H.Uid) {
  272. #ifdef DEBUG
  273.             fprintf(stderr, "uid wrong\n");
  274. #endif
  275.             continue;
  276.         }
  277.  
  278.         /*
  279.          * Saved the day!
  280.          */
  281.         enter(fp++, dirent->d_name, ecount);
  282.         ecount++;
  283. #ifdef DEBUG
  284.         fprintf(stderr, "entered file %s\n", dirent->d_name);
  285. #endif
  286.     }
  287.     ignore(closedir(dir));
  288.  
  289.     /*
  290.      * If any files were saved, then sort them and print
  291.      * them out.
  292.      */
  293.     if (ecount == 0) {
  294.         fprintf(stderr, "No files saved.\n");
  295.         return;
  296.     }
  297.     qsort(&svbuf[0], ecount, sizeof svbuf[0], qucmp);
  298.     for (fp = &svbuf[0]; fp < &svbuf[ecount]; fp++) {
  299.         cp = ctime(&fp->sf_time);
  300.         cp[10] = 0;
  301.         fprintf(stderr, "On %s at ", cp);
  302.          cp[16] = 0;
  303.         fprintf(stderr, &cp[11]);
  304.         fprintf(stderr, " saved %d lines of file \"%s\"\n",
  305.             fp->sf_lines, fp->sf_name);
  306.     }
  307. }
  308.  
  309. /*
  310.  * Enter a new file into the saved file information.
  311.  */
  312. enter(fp, fname, count)
  313.     struct svfile *fp;
  314.     char *fname;
  315. {
  316.     register char *cp, *cp2;
  317.     register struct svfile *f, *fl;
  318.     time_t curtime, itol();
  319.  
  320.     f = 0;
  321.     if (count >= NENTRY) {
  322.         /*
  323.          * My god, a huge number of saved files.
  324.          * Would you work on a system that crashed this
  325.          * often?  Hope not.  So lets trash the oldest
  326.          * as the most useless.
  327.          *
  328.          * (I wonder if this code has ever run?)
  329.          */
  330.         fl = fp - count + NENTRY - 1;
  331.         curtime = fl->sf_time;
  332.         for (f = fl; --f > fp-count; )
  333.             if (f->sf_time < curtime)
  334.                 curtime = f->sf_time;
  335.         for (f = fl; --f > fp-count; )
  336.             if (f->sf_time == curtime)
  337.                 break;
  338.         fp = f;
  339.     }
  340.  
  341.     /*
  342.      * Gotcha.
  343.      */
  344.     fp->sf_time = H.Time;
  345.     fp->sf_lines = H.Flines;
  346.     for (cp2 = fp->sf_name, cp = savedfile; *cp;)
  347.         *cp2++ = *cp++;
  348.     for (cp2 = fp->sf_entry, cp = fname; *cp && cp-fname < 14;)
  349.         *cp2++ = *cp++;
  350.     *cp2++ = 0;
  351. }
  352.  
  353. /*
  354.  * Do the qsort compare to sort the entries first by file name,
  355.  * then by modify time.
  356.  */
  357. qucmp(p1, p2)
  358.     struct svfile *p1, *p2;
  359. {
  360.     register int t;
  361.  
  362.     if (t = strcmp(p1->sf_name, p2->sf_name))
  363.         return(t);
  364.     if (p1->sf_time > p2->sf_time)
  365.         return(-1);
  366.     return(p1->sf_time < p2->sf_time);
  367. }
  368.  
  369. /*
  370.  * Scratch for search.
  371.  */
  372. char    bestnb[BUFSIZ];        /* Name of the best one */
  373. long    besttime;        /* Time at which the best file was saved */
  374. int    bestfd;            /* Keep best file open so it dont vanish */
  375.  
  376. /*
  377.  * Look for a file, both in the users directory option value
  378.  * (i.e. usually /tmp) and in usrpath(spool/preserve).
  379.  * Want to find the newest so we search on and on.
  380.  */
  381. findtmp(dir)
  382.     char *dir;
  383. {
  384.  
  385.     /*
  386.      * No name or file so far.
  387.      */
  388.     bestnb[0] = 0;
  389.     bestfd = -1;
  390.  
  391.     /*
  392.      * Search usrpath(spool/preserve) and, if we can get there, /tmp
  393.      * (actually the users "directory" option).
  394.      */
  395.     searchdir(dir);
  396.     if (chdir(mydir) == 0)
  397.         searchdir(mydir);
  398.     if (bestfd != -1) {
  399.         /*
  400.          * Gotcha.
  401.          * Put the file (which is already open) in the file
  402.          * used by the temp file routines, and save its
  403.          * name for later unlinking.
  404.          */
  405.         tfile = bestfd;
  406.         CP(nb, bestnb);
  407.         ignorl(lseek(tfile, 0l, 0));
  408.  
  409.         /*
  410.          * Gotta be able to read the header or fall through
  411.          * to lossage.
  412.          */
  413.         if (read(tfile, (char *) &H, sizeof H) == sizeof H)
  414.             return;
  415.     }
  416.  
  417.     /*
  418.      * Extreme lossage...
  419.      */
  420.     error(" File not found", 0);
  421. }
  422.  
  423. /*
  424.  * Search for the file in directory dirname.
  425.  *
  426.  * Don't chdir here, because the users directory
  427.  * may be ".", and we would move away before we searched it.
  428.  * Note that we actually chdir elsewhere (because it is too slow
  429.  * to look around in usrpath(spool/preserve) without chdir'ing there) so we
  430.  * can't win, because we don't know the name of '.' and if the path
  431.  * name of the file we want to unlink is relative, rather than absolute
  432.  * we won't be able to find it again.
  433.  */
  434. searchdir(dirname)
  435.     char *dirname;
  436. {
  437.     struct direct *dirent;
  438.     register DIR *dir;
  439.     char dbuf[BUFSIZ];
  440.  
  441.     dir = opendir(dirname);
  442.     if (dir == NULL)
  443.         return;
  444.     while ((dirent = readdir(dir)) != NULL) {
  445.         if (dirent->d_name[0] != 'E')
  446.             continue;
  447.         /*
  448.          * Got a file in the directory starting with E...
  449.          * Save a consed up name for the file to unlink
  450.          * later, and check that this is really a file
  451.          * we are looking for.
  452.          */
  453.         ignore(strcat(strcat(strcpy(nb, dirname), "/"), dirent->d_name));
  454.         if (yeah(nb)) {
  455.             /*
  456.              * Well, it is the file we are looking for.
  457.              * Is it more recent than any version we found before?
  458.              */
  459.             if (H.Time > besttime) {
  460.                 /*
  461.                  * A winner.
  462.                  */
  463.                 ignore(close(bestfd));
  464.                 bestfd = dup(tfile);
  465.                 besttime = H.Time;
  466.                 CP(bestnb, nb);
  467.             }
  468.             /*
  469.              * Count versions so user can be told there are
  470.              * ``yet more pages to be turned''.
  471.              */
  472.             vercnt++;
  473.         }
  474.         ignore(close(tfile));
  475.     }
  476.     ignore(closedir(dir));
  477. }
  478.  
  479. /*
  480.  * Given a candidate file to be recovered, see
  481.  * if its really an editor temporary and of this
  482.  * user and the file specified.
  483.  */
  484. yeah(name)
  485.     char *name;
  486. {
  487.  
  488.     tfile = open(name, 2);
  489.     if (tfile < 0)
  490.         return (0);
  491.     if (read(tfile, (char *) &H, sizeof H) != sizeof H) {
  492. nope:
  493.         ignore(close(tfile));
  494.         return (0);
  495.     }
  496.     if (!eq(savedfile, file))
  497.         goto nope;
  498.     if (getuid() != H.Uid)
  499.         goto nope;
  500.     /*
  501.      * This is old and stupid code, which
  502.      * puts a word LOST in the header block, so that lost lines
  503.      * can be made to point at it.
  504.      */
  505.     ignorl(lseek(tfile, (long)(BUFSIZ*HBLKS-8), 0));
  506.     ignore(write(tfile, "LOST", 5));
  507.     return (1);
  508. }
  509.  
  510. preserve()
  511. {
  512.  
  513. }
  514.  
  515. /*
  516.  * Find the true end of the scratch file, and ``LOSE''
  517.  * lines which point into thin air.  This lossage occurs
  518.  * due to the sandbagging of i/o which can cause blocks to
  519.  * be written in a non-obvious order, different from the order
  520.  * in which the editor tried to write them.
  521.  *
  522.  * Lines which are lost are replaced with the text LOST so
  523.  * they are easy to find.  We work hard at pretty formatting here
  524.  * as lines tend to be lost in blocks.
  525.  *
  526.  * This only seems to happen on very heavily loaded systems, and
  527.  * not very often.
  528.  */
  529. scrapbad()
  530. {
  531.     register line *ip;
  532.     struct stat stbuf;
  533.     off_t size, maxt;
  534.     int bno, cnt, bad, was;
  535.     char bk[BUFSIZ];
  536.  
  537.     ignore(fstat(tfile, &stbuf));
  538.     size = stbuf.st_size;
  539.     maxt = (size >> SHFT) | (BNDRY-1);
  540.     bno = (maxt >> OFFBTS) & BLKMSK;
  541. #ifdef DEBUG
  542.     fprintf(stderr, "size %ld, maxt %o, bno %d\n", size, maxt, bno);
  543. #endif
  544.  
  545.     /*
  546.      * Look for a null separating two lines in the temp file;
  547.      * if last line was split across blocks, then it is lost
  548.      * if the last block is.
  549.      */
  550.     while (bno > 0) {
  551.         ignorl(lseek(tfile, (long) BUFSIZ * bno, 0));
  552.         cnt = read(tfile, (char *) bk, BUFSIZ);
  553.         while (cnt > 0)
  554.             if (bk[--cnt] == 0)
  555.                 goto null;
  556.         bno--;
  557.     }
  558. null:
  559.  
  560.     /*
  561.      * Magically calculate the largest valid pointer in the temp file,
  562.      * consing it up from the block number and the count.
  563.      */
  564.     maxt = ((bno << OFFBTS) | (cnt >> SHFT)) & ~1;
  565. #ifdef DEBUG
  566.     fprintf(stderr, "bno %d, cnt %d, maxt %o\n", bno, cnt, maxt);
  567. #endif
  568.  
  569.     /*
  570.      * Now cycle through the line pointers,
  571.      * trashing the Lusers.
  572.      */
  573.     was = bad = 0;
  574.     for (ip = one; ip <= dol; ip++)
  575.         if (*ip > maxt) {
  576. #ifdef DEBUG
  577.             fprintf(stderr, "%d bad, %o > %o\n", ip - zero, *ip, maxt);
  578. #endif
  579.             if (was == 0)
  580.                 was = ip - zero;
  581.             *ip = ((HBLKS*BUFSIZ)-8) >> SHFT;
  582.         } else if (was) {
  583.             if (bad == 0)
  584.                 fprintf(stderr, " [Lost line(s):");
  585.             fprintf(stderr, " %d", was);
  586.             if ((ip - 1) - zero > was)
  587.                 fprintf(stderr, "-%d", (ip - 1) - zero);
  588.             bad++;
  589.             was = 0;
  590.         }
  591.     if (was != 0) {
  592.         if (bad == 0)
  593.             fprintf(stderr, " [Lost line(s):");
  594.         fprintf(stderr, " %d", was);
  595.         if (dol - zero != was)
  596.             fprintf(stderr, "-%d", dol - zero);
  597.         bad++;
  598.     }
  599.     if (bad)
  600.         fprintf(stderr, "]");
  601. }
  602.  
  603. /*
  604.  * Aw shucks, if we only had a (void) cast.
  605.  */
  606. #ifdef lint
  607. Ignorl(a)
  608.     long a;
  609. {
  610.  
  611.     a = a;
  612. }
  613.  
  614. Ignore(a)
  615.     char *a;
  616. {
  617.  
  618.     a = a;
  619. }
  620.  
  621. Ignorf(a)
  622.     int (*a)();
  623. {
  624.  
  625.     a = a;
  626. }
  627.  
  628. ignorl(a)
  629.     long a;
  630. {
  631.  
  632.     a = a;
  633. }
  634. #endif
  635.  
  636. int    cntch, cntln, cntodd, cntnull;
  637. /*
  638.  * Following routines stolen mercilessly from ex.
  639.  */
  640. putfile()
  641. {
  642.     line *a1;
  643.     register char *fp, *lp;
  644.     register int nib;
  645.  
  646.     a1 = addr1;
  647.     clrstats();
  648.     cntln = addr2 - a1 + 1;
  649.     if (cntln == 0)
  650.         return;
  651.     nib = BUFSIZ;
  652.     fp = genbuf;
  653.     do {
  654.         getline(*a1++);
  655.         lp = linebuf;
  656.         for (;;) {
  657.             if (--nib < 0) {
  658.                 nib = fp - genbuf;
  659.                 if (write(io, genbuf, nib) != nib)
  660.                     wrerror();
  661.                 cntch += nib;
  662.                 nib = 511;
  663.                 fp = genbuf;
  664.             }
  665.             if ((*fp++ = *lp++) == 0) {
  666.                 fp[-1] = '\n';
  667.                 break;
  668.             }
  669.         }
  670.     } while (a1 <= addr2);
  671.     nib = fp - genbuf;
  672.     if (write(io, genbuf, nib) != nib)
  673.         wrerror();
  674.     cntch += nib;
  675. }
  676.  
  677. wrerror()
  678. {
  679.  
  680.     syserror();
  681. }
  682.  
  683. clrstats()
  684. {
  685.  
  686.     ninbuf = 0;
  687.     cntch = 0;
  688.     cntln = 0;
  689.     cntnull = 0;
  690.     cntodd = 0;
  691. }
  692.  
  693. #define    READ    0
  694. #define    WRITE    1
  695.  
  696. getline(tl)
  697.     line tl;
  698. {
  699.     register char *bp, *lp;
  700.     register int nl;
  701.  
  702.     lp = linebuf;
  703.     bp = getblock(tl, READ);
  704.     nl = nleft;
  705.     tl &= ~OFFMSK;
  706.     while (*lp++ = *bp++)
  707.         if (--nl == 0) {
  708.             bp = getblock(tl += INCRMT, READ);
  709.             nl = nleft;
  710.         }
  711. }
  712.  
  713. int    read();
  714. int    write();
  715.  
  716. char *
  717. getblock(atl, iof)
  718.     line atl;
  719.     int iof;
  720. {
  721.     register int bno, off;
  722.     
  723.     bno = (atl >> OFFBTS) & BLKMSK;
  724.     off = (atl << SHFT) & LBTMSK;
  725.     if (bno >= NMBLKS)
  726.         error(" Tmp file too large");
  727.     nleft = BUFSIZ - off;
  728.     if (bno == iblock) {
  729.         ichanged |= iof;
  730.         return (ibuff + off);
  731.     }
  732.     if (bno == oblock)
  733.         return (obuff + off);
  734.     if (iof == READ) {
  735.         if (ichanged)
  736.             blkio(iblock, ibuff, write);
  737.         ichanged = 0;
  738.         iblock = bno;
  739.         blkio(bno, ibuff, read);
  740.         return (ibuff + off);
  741.     }
  742.     if (oblock >= 0)
  743.         blkio(oblock, obuff, write);
  744.     oblock = bno;
  745.     return (obuff + off);
  746. }
  747.  
  748. blkio(b, buf, iofcn)
  749.     short b;
  750.     char *buf;
  751.     int (*iofcn)();
  752. {
  753.  
  754.     lseek(tfile, (long) (unsigned) b * BUFSIZ, 0);
  755.     if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ)
  756.         syserror();
  757. }
  758.  
  759. syserror()
  760. {
  761.     extern int sys_nerr;
  762.     extern char *sys_errlist[];
  763.  
  764.     dirtcnt = 0;
  765.     write(2, " ", 1);
  766.     if (errno >= 0 && errno <= sys_nerr)
  767.         error(sys_errlist[errno]);
  768.     else
  769.         error("System error %d", errno);
  770.     exit(1);
  771. }
  772.  
  773. /*
  774.  * Must avoid stdio because expreserve uses sbrk to do memory
  775.  * allocation and stdio uses malloc.
  776.  */
  777. fprintf(fp, fmt, a1, a2, a3, a4, a5)
  778.     FILE *fp;
  779.     char *fmt;
  780.     char *a1, *a2, *a3, *a4, *a5;
  781. {
  782.     char buf[BUFSIZ];
  783.  
  784.     if (fp != stderr)
  785.         return;
  786.     sprintf(buf, fmt, a1, a2, a3, a4, a5);
  787.     write(2, buf, strlen(buf));
  788. }
  789.